<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BGroup
 *
 * @author I062261
 */
class BGroup extends BTreeEntity {

    const Type_Group = 'type';

    public $name = null;
    public $className = null;

    /**
     * 
     * @param BEntity $member, member should be obj
     * @param BRepositoryContext $data
     * @return boolean
     */
    public function addMember($member, $member2 = NULL, $context = NULL) {

        //parent::addMember($member, $context);
        if ($member instanceof BEntity) {
            $memberRow = $member->getRepository()->getRow();
            $member2Row = NULL;
            if ($member2 instanceof BEntity)
                $member2Row = $member2->getRepository()->getRow();
            if (is_array($context) && $context != NULL)
                $context = $member->getRepository()->propertyListToAttributeList($context);
            $this->getRepository()->getRow()->addMember($memberRow, $member2Row, $context);
        }
    }

    public function addChildGroup($item, $data = NULL) {
        return parent::addChildItem($item, $data);
    }

    /**
     * get member for current group obj, if set recursive, get all children member
     * @param type $context
     * @param type $recursive
     * @return boolean
     */
    public function getMembers($memberContext = null, $recursive = FALSE) {
        if ($memberContext instanceof BEntity) {
            $memberRowContext = $memberContext->getRepository()->getRow();
            $memberRowList = $this->getRepository()->getRow()->getMembers($memberRowContext);
            $members = array();
            foreach ($memberRowList as $row) {
                $member = clone $memberContext;
                $member->load($row);
                $members[$member->getId()] = $member;
            }
            return $members;
        }
        if (is_array($memberContext)) {
            $member1 = isset($memberContext['member1']) ? $memberContext['member1'] : NULL;
            $member2 = isset($memberContext['member1']) ? $memberContext['member1'] : NULL;
            $returnIndex = isset($memberContext['returnIndex']) ? $memberContext['returnIndex'] : NULL;
            $memberRowContext = array();
            if ($member1 instanceof BEntity)
                $memberRowContext['memberRow'] = $member1->getRepository()->getRow();
            if ($member2 instanceof BEntity)
                $memberRowContext['member2Row'] = $member2->getRepository()->getRow();
            if ($returnIndex != NULL)
                $memberRowContext['returnIndex'] = $returnIndex;
            $memberRowList = $this->getRepository()->getRow()->getMembers(array('memberRow' => $memberRowContext));
            $members = array();
            foreach ($memberRowList as $row) {
                $member = clone $memberContext;
                $member->load($row);
                $members[$member->getId()] = $member;
            }
            return $members;
        }
    }

    public function getMember($memberContext = NULL, $recursive = FALSE) {

        $members = $this->getMembers($memberContext, $recursive);

        if (is_array($members) && $members != NULL)
            return reset($members);

        return FALSE;
    }

    /**
     * support nested name
     * @param type $name
     * @param type $context
     * @param type $memberContext
     */
    public function addMemberByName($name, $groupContext = NULL, $memberContext = NULL) {

        $memberName = $name;

        $names = preg_split(BTreeEntity::Pattern_Delimiter, $name);

        $parent = $this;

        //if name is a nested name, find group first, if can not find group, create it
        if (count($names) > 1) {
            //caculate group name
            $memberName = end($names);
            $key = key($names);
            unset($names[$key]);

            //add group, if not find, add new
            foreach ($names as $tName) {
                if (is_array($groupContext))
                    $groupContext['name'] = $tName;
                if ($groupContext instanceof BGroup)
                    $groupContext->name = $tName;
                //$context = array('name' => $tName, 'ownerClass' => get_class($this->owner));
                $tParent = $parent->getChild($groupContext);
                if ($tParent == NULL) {
                    $parent->addChildItem($groupContext);
                    $tParent = $parent->getChild($groupContext);
                }
                $parent = $tParent;
            }
            //$parentGroup = $parent;
        }

        if ($memberContext instanceof BEntityWithGroup) {
            $memberContext->name = $memberName;
        }
        if (is_array($memberContext)) {
            $memberContext['name'] = $memberName;
        }

        $findMember = $parent->getMember($memberContext);
        if ($findMember != NULL) {
            //save value for member
            $findMember->save($memberContext);
            return;
        }

        $member = NULL;
        //else create new member and add it to group
        if ($memberContext instanceof BEntityWithGroup) {
            $member = $memberContext;
            $member->save();
        }
        if (is_array($memberContext)) {
            $memberClass = isset($memberContext['memberClass']) ? $memberContext['memberClass'] : str_replace('Group', '', get_class($this));
            $member = new $memberClass();
            $member->save($memberContext);
        }

        if ($member != NULL)
            $parent->addMember($member);
    }

    /**
     * find member by member name
     * @param type $memberName
     * @param type $memberContext
     */
    public function getMemberByName($memberName, $memberContext = NULL, $parentContext = NULL) {

        $names = preg_split(BTreeEntity::Pattern_Delimiter, $memberName);

        $group = $this;

        if (count($names) > 1) {
            //$oNames = $names;
            $memberName = end($names);
            $key = key($names);
            unset($names[$key]);

            $groupName = NULL;
            foreach ($names as $name) {
                if ($groupName == NULL)
                    $groupName.=$name;
                if ($groupName != NULL)
                    $groupName .= '.' . $name;
            }

            if ($groupName != NULL) {
                $groups = $this->getChildrenByPath($groupName, $parentContext);
                $group = $groups[0];
            }
        }

        $members = $group->getMembers(array('name' => $memberName));

        if ($memberContext instanceof BEntity) {
            $properties = get_object_vars($memberContext);
            $finalMembers = array();
            if ($properties != NULL) {
                foreach ($members as $id => $member) {
                    $isChoosed = TRUE;
                    foreach ($properties as $key => $value) {
                        if ($value != NULL) {
                            if ($member->$key != $value)
                                $isChoosed = FALSE;
                        }
                    }

                    if ($isChoosed) {
                        $finalMembers[$id] = $member;
                    }
                }
                if ($finalMembers != NULL)
                    return reset($finalMembers);
                //return $finalMembers;
            }
        }

        if (is_array($memberContext)) {
            $finalmembers = array();
            foreach ($members as $member) {
                $isChoosed = TRUE;
                foreach ($memberContext as $property => $value) {
                    if ($member->$property != $value)
                        $isChoosed = FALSE;
                }
                if ($isChoosed)
                    $finalmembers[$member->getId()] = $member;
            }
            if ($finalMembers != NULL)
                return reset($finalmembers);
            //return $finalmembers;
        }

        if ($members != NULL)
            return reset($members);

        return FALSE;
    }

    /**
     * add array of data into group and member table
     * @param type $nestedMembers
     * @param type $groupContext
     * @param type $memberContext
     */
    public function addNestedMembersByArray($nestedMembers, $groupContext = null, $memberContext = null, $context = array()) {
        //$configGroups = BConfigGroup::findAll(array());
        $theMemberContext = $memberContext;
        $theGroupContext = $groupContext;
        //if ($parentGroup == NULL) {
        //$parentGroup = $this;
        //}
        foreach ($nestedMembers as $name => $value) {
            if (is_string($value) && !is_numeric($name)) {
                $valueProperty = 'value';
                if (isset($context['memberValueProperty']) && $context['memberValueProperty'] != NULL)
                    $valueProperty = $context['memberValueProperty'];
                //add value into memberContext for add later
                if ($theMemberContext instanceof BEntity) {
                    $theMemberContext->$valueProperty = $value;
                    if ($theMemberContext->name != $name)
                        $theMemberContext->name = $name;
                    $theMemberContext->id = NULL;
                }
                if (is_array($theMemberContext)) {
                    $theMemberContext[$valueProperty] = $value;
                    if ($theMemberContext['name'] != $name)
                        $theMemberContext['name'] = $name;
                    $theMemberContext['id'] = NULL;
                }
                $this->addMemberByName($name, $theGroupContext, $theMemberContext);
                continue;
            }
            if (is_array($value) && !is_numeric($name)) {
                $isNested = FALSE;
                foreach ($value as $key => $item) {
                    if (!is_numeric($key)) {
                        //if all value is string value, add them as value, for example, add 'name'=>array('test1','test2'....) as member with name of 'name
                        $isNested = TRUE;
                    } else {
                        //valueProperty means: what property in member class map to value in array                        
                        $valueProperty = 'value';
                        if (isset($context['memberValueProperty']) && $context['memberValueProperty'] != NULL) {
                            $valueProperty = $context['memberValueProperty'];
                        }
                        if ($theMemberContext instanceof BEntity) {
                            $newMemberContext = clone $theMemberContext;
                            $newMemberContext->id = NULL;
                            $newMemberContext->$valueProperty = $item;
                        }
                        if (is_array($theMemberContext)) {
                            $newMemberContext = $theMemberContext;
                            $newMemberContext[$valueProperty] = $item;
                            $newMemberContext['id'] = NULL;
                        }
                        $this->addMemberByName($name, $theGroupContext, $newMemberContext);
                    }
                }
                if ($isNested) {
                    if ($theGroupContext instanceof BGroup) {
                        $theGroupContext->id = NULL;
                        $theGroupContext->name = $name;
                    }
                    if (is_array($theGroupContext)) {
                        $theGroupContext['id'] = NULL;
                        $theGroupContext['name'] = $name;
                    }
                    $tGroup = $this->getChild($theGroupContext);
                    if ($tGroup != NULL)
                        $group = $tGroup;
                    else {
                        $class = get_class($this);
                        if (is_array($theGroupContext)) {
                            $group = new $class();
                            $group->name = $name;
                            $group->save($theGroupContext);
                        }
                        if ($theGroupContext instanceof $class) {
                            $group = new $class();
                            //$group = $theGroupContext;
                            $group->name = $name;
                            $group->save($theGroupContext);
                        }
                        $this->addChild($group);
                    }
                    //$parentGroup = $group;
                    $group->addNestedMembersByArray($value, $theGroupContext, $theMemberContext, $context);
                }
            }
        }
    }

    /**
     * support nested name
     * @param type $name
     * @param type $groupContext
     * @return type
     */
    public function addChildByName($name, $groupContext = NULL) {
        $names = preg_split(BTreeEntity::Pattern_Delimiter, $name);

        //if name is a nested name, find group first, if can not find group, create it
        //caculate group name         
        $parent = $this;
        //add group, if not find, add new
        foreach ($names as $tName) {
            if (is_array($groupContext))
                $groupContext['name'] = $tName;
            if ($groupContext instanceof BGroup)
                $groupContext->name = $tName;
            //$context = array('name' => $tName, 'ownerClass' => get_class($this->owner));
            $tParent = $parent->getChild($groupContext);
            if ($tParent == NULL) {
                $parent->addChildItem($groupContext);
                $tParent = $parent->getChild($groupContext);
            }
            $parent = $tParent;
        }
        return $parent;
    }

    /**
     * name can be nested name
     * @param type $name
     * @param BGroup $filterContext
     * @return type
     */
    public function getChildrenByPath($name, $filterContext = array()) {
        $child = $this->getChildByName($name, $filterContext);

        $children = array();

        if ($child != NULL)
            $children = $child->getChildren($filterContext);

        return $children;
    }

    public function getChildByName($name, $filterContext = NULL) {
        $context = array();

        $context['name'] = $name;
        if (isset($this->spaceId) && $this->spaceId != NULL)
            $context['spaceId'] = $this->spaceId;
        if (isset($this->appId) && $this->appId != NULL)
            $context['appId'] = $this->appId;

        //$child = $this->getChildByName($name,$filterContext);
        //$children = $this->getChildren($filterContext);
        //first get all children by name
        $children = $this->getChildren($context);

        if ($children != NULL) {
            $finalChildren = array();
            if (is_array($filterContext)) {
                foreach ($children as $child) {
                    $isChoosed = TRUE;
                    foreach ($filterContext as $property => $value) {
                        if ($child->$property != $value)
                            $isChoosed = FALSE;
                    }
                    if ($isChoosed)
                        $finalChildren[$child->getId()] = $child;
                }
                if ($finalChildren != NULL)
                    return reset($finalChildren);
            }

            if ($filterContext instanceof BGroup) {
                $properties = get_object_vars($filterContext);
                $finalGroups = array();
                if ($properties != NULL) {
                    foreach ($children as $id => $child) {
                        $isChoosed = TRUE;
                        foreach ($properties as $key => $value) {
                            if ($value != NULL) {
                                if ($child->$key != $value)
                                    $isChoosed = FALSE;
                            }
                        }

                        if ($isChoosed) {
                            $finalGroups[$id] = $child;
                        }
                    }
                    if ($finalChildren != NULL)
                        return reset($finalGroups);
                }
            }

            if ($children != NULL)
                return reset($children);
        }

        return FALSE;
    }

    public function removeMember($member = null, $context = NULL) {
        $groupRow = $this->getRepository()->getRow();
        if ($member instanceof BEntity) {
            $memberRow = $member->getRepository->getRow();
            if ($groupRow instanceof BRow)
                return $groupRow->removeMember($memberContext);
        }
        return FALSE;
    }

    public static function removeMembersByMemberId($memberId) {
        $class = get_called_class();
        BRepositoryFactory::createRepository2()->removeGroupMembersByMemberId($class, $memberId);
    }

    public function haveMember($member) {

        return $member->isMemberOf($this);

        //$members = $this->getMembers(array('memberClass'=>  get_class($member)));
    }

    /**
     * this function will return members according to name
     * @param type $context
     */
    public static function findMember($context = NULL) {

        $context = BRepository::getContext($context);

        $groupClass = get_called_class();

        $name = $context->name;

        //default, set root as parent
        $parent = new $groupClass(1);

        if ($context->parent != NULL)
            $parent = $context->parent;

        if ($name != NULL) {
            $names = preg_split('[' . BTreeEntity::delimiter . ']', $name);
            //find obj by name
            $count = count($names);

            if ($count == 1)
                return $parent->getMember($context);

            //if count > 1
            $memberName = $context->memberName;
            $groupName = $context->groupName;
            //delete symbol if end with /\.|
            //$name = preg_replace('/[' . BTreeDataObj::delimiter . ']/', $name, '');
            $context->name = $groupName;
            $context->parent = $parent;

            $parent = self::find($context);

            if ($parent instanceof BGroup) {
                $context->name = $memberName;
                return $parent->getMember($context);
            }
        }
    }

    public function initTreeEntityBeforeFirstLoad($data = NULL) {
        //$count = 0;
        if (method_exists($this, 'initGroupBeforeFirstLoad'))
            $this->initGroupBeforeFirstLoad($data);
    }

    public function initGroupBeforeFirstLoad($data = NULL) {
        //return $this->initTreeEntityBeforeFirstLoad($data);
    }

    public function getRepository($data = NULL, $reload = FALSE) {
        $repository = parent::getRepository($data, $reload);
        $repository->addPropertyToColumnMap('memberType', 'member_type');
        return $repository;
    }

}

?>
